﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Threading;
using System.Xml;
using System.Linq;
//using System.Xml.Linq;
using System.Diagnostics;
using System.Text.RegularExpressions;


namespace CommonUtils
{
	public class StringUtils
	{
		static StringUtils()
		{
			InitVNCharsMap();
		}

		#region // Vietnamese:
		private static Hashtable s_htVNCharsMap = null;
		private static void InitVNCharsMap()
		{
			s_htVNCharsMap = new Hashtable(200);
			s_htVNCharsMap.Add('A', 'A'); s_htVNCharsMap.Add('Á', 'A'); s_htVNCharsMap.Add('À', 'A'); s_htVNCharsMap.Add('Ả', 'A'); s_htVNCharsMap.Add('Ã', 'A'); s_htVNCharsMap.Add('Ạ', 'A');
			s_htVNCharsMap.Add('Ă', 'A'); s_htVNCharsMap.Add('Ắ', 'A'); s_htVNCharsMap.Add('Ằ', 'A'); s_htVNCharsMap.Add('Ẳ', 'A'); s_htVNCharsMap.Add('Ẵ', 'A'); s_htVNCharsMap.Add('Ặ', 'A');
			s_htVNCharsMap.Add('Â', 'A'); s_htVNCharsMap.Add('Ấ', 'A'); s_htVNCharsMap.Add('Ầ', 'A'); s_htVNCharsMap.Add('Ẩ', 'A'); s_htVNCharsMap.Add('Ẫ', 'A'); s_htVNCharsMap.Add('Ậ', 'A');
			s_htVNCharsMap.Add('B', 'B');
			s_htVNCharsMap.Add('C', 'C');
			s_htVNCharsMap.Add('D', 'D');
			s_htVNCharsMap.Add('Đ', 'D');
			s_htVNCharsMap.Add('E', 'E'); s_htVNCharsMap.Add('É', 'E'); s_htVNCharsMap.Add('È', 'E'); s_htVNCharsMap.Add('Ẻ', 'E'); s_htVNCharsMap.Add('Ẽ', 'E'); s_htVNCharsMap.Add('Ẹ', 'E');
			s_htVNCharsMap.Add('Ê', 'E'); s_htVNCharsMap.Add('Ế', 'E'); s_htVNCharsMap.Add('Ề', 'E'); s_htVNCharsMap.Add('Ể', 'E'); s_htVNCharsMap.Add('Ễ', 'E'); s_htVNCharsMap.Add('Ệ', 'E');
			s_htVNCharsMap.Add('F', 'F');
			s_htVNCharsMap.Add('G', 'G');
			s_htVNCharsMap.Add('H', 'H');
			s_htVNCharsMap.Add('I', 'I'); s_htVNCharsMap.Add('Í', 'I'); s_htVNCharsMap.Add('Ì', 'I'); s_htVNCharsMap.Add('Ỉ', 'I'); s_htVNCharsMap.Add('Ĩ', 'I'); s_htVNCharsMap.Add('Ị', 'I');
			s_htVNCharsMap.Add('J', 'J');
			s_htVNCharsMap.Add('K', 'K');
			s_htVNCharsMap.Add('L', 'L');
			s_htVNCharsMap.Add('M', 'M');
			s_htVNCharsMap.Add('N', 'N');
			s_htVNCharsMap.Add('O', 'O'); s_htVNCharsMap.Add('Ó', 'O'); s_htVNCharsMap.Add('Ò', 'O'); s_htVNCharsMap.Add('Ỏ', 'O'); s_htVNCharsMap.Add('Õ', 'O'); s_htVNCharsMap.Add('Ọ', 'O');
			s_htVNCharsMap.Add('Ô', 'O'); s_htVNCharsMap.Add('Ố', 'O'); s_htVNCharsMap.Add('Ồ', 'O'); s_htVNCharsMap.Add('Ổ', 'O'); s_htVNCharsMap.Add('Ỗ', 'O'); s_htVNCharsMap.Add('Ộ', 'O');
			s_htVNCharsMap.Add('Ơ', 'O'); s_htVNCharsMap.Add('Ớ', 'O'); s_htVNCharsMap.Add('Ờ', 'O'); s_htVNCharsMap.Add('Ở', 'O'); s_htVNCharsMap.Add('Ỡ', 'O'); s_htVNCharsMap.Add('Ợ', 'O');
			s_htVNCharsMap.Add('P', 'P');
			s_htVNCharsMap.Add('Q', 'Q');
			s_htVNCharsMap.Add('R', 'R');
			s_htVNCharsMap.Add('S', 'S');
			s_htVNCharsMap.Add('T', 'T');
			s_htVNCharsMap.Add('U', 'U'); s_htVNCharsMap.Add('Ú', 'U'); s_htVNCharsMap.Add('Ù', 'U'); s_htVNCharsMap.Add('Ủ', 'U'); s_htVNCharsMap.Add('Ũ', 'U'); s_htVNCharsMap.Add('Ụ', 'U');
			s_htVNCharsMap.Add('Ư', 'U'); s_htVNCharsMap.Add('Ứ', 'U'); s_htVNCharsMap.Add('Ừ', 'U'); s_htVNCharsMap.Add('Ử', 'U'); s_htVNCharsMap.Add('Ữ', 'U'); s_htVNCharsMap.Add('Ự', 'U');
			s_htVNCharsMap.Add('V', 'V');
			s_htVNCharsMap.Add('W', 'W');
			s_htVNCharsMap.Add('X', 'X');
			s_htVNCharsMap.Add('Y', 'Y'); s_htVNCharsMap.Add('Ý', 'Y'); s_htVNCharsMap.Add('Ỳ', 'Y'); s_htVNCharsMap.Add('Ỷ', 'Y'); s_htVNCharsMap.Add('Ỹ', 'Y'); s_htVNCharsMap.Add('Ỵ', 'Y');
			s_htVNCharsMap.Add('Z', 'Z');
		}
		private static char CharVN2CharEN(char c)
		{
			object obj = s_htVNCharsMap[c];
			if (obj == null) return c;
			return (char)obj;
		}
		public static string StringVN2StringEN(string strVN)
		{
			if (strVN == null || strVN.Length == 0) return strVN;
			string str = strVN.ToUpper(new System.Globalization.CultureInfo("vi-VN"));
			StringBuilder strbd = new StringBuilder(200);
			for (int i = 0; i < str.Length; i++)
			{
				strbd.Append(CharVN2CharEN(str[i]));
			}
			return strbd.ToString();
		}

		/// <summary>
		/// Translate number to String (for read currency)
		/// Ex : strTmp = LongInt2VNSpeakString(Convert.ToInt64(this.textBox1.Text), "Đồng");
		/// </summary>
		/// <param name="So">Number need translate</param>
		/// <param name="DVT">Đồng</param>
		/// <returns>Viet Namese String</returns>
		public static string LongInt2VNSpeakString(long So, string DVT)
		{

			if (So.ToString().Length > 18)
			{
				return "Số quá lớn";
			}
			else if (So == 0)
			{
				return "Không " + DVT;
			}
			else
			{
				string KQ = "";
				string[] donvi = { DVT, "ngàn", "triệu", "tỷ", "ngàn tỷ", "triệu tỷ" };
				string[] chuso = { "không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín" };
				if (So.ToString().Length > 3)
				{
					int ind;
					int sonhom;
					long tmp;
					sonhom = So.ToString().Length / 3;
					if (So.ToString().Length % 3 > 0)
					{
						sonhom += 1;
					}
					for (ind = 0; ind <= sonhom - 1; ind++)
					{
						tmp = (So / System.Convert.ToInt64(Math.Pow(1000, ind))) % 1000;
						if (tmp > 0)
						{
							if (ind > 0)
							{
								if (KQ == donvi[0])
								{
									KQ = LongInt2VNSpeakString(tmp, donvi[ind]) + " " + KQ.ToLower();
								}
								else
								{
									KQ = LongInt2VNSpeakString(tmp, donvi[ind]) + ", " + KQ.ToLower();
								}
							}
							else
							{
								KQ = LongInt2VNSpeakString(tmp, donvi[ind]);
							}
						}
						else if (ind == 0)
						{
							KQ = donvi[0];
						}
					}
					return KQ;
				}
				else
				{
					int tram;
					int chuc;
					int dv;
					tram = System.Convert.ToInt32((So / 100) % 10);
					chuc = System.Convert.ToInt32((So / 10) % 10);
					dv = System.Convert.ToInt32(So % 10);
					string tmp = "";
					if (tram == 0 & chuc == 0)
					{
						tmp = chuso[dv] + " " + DVT;
						//tmp = Microsoft.VisualBasic.Left(tmp, 1).ToUpper + tmp.Substring(1);
						tmp = tmp.Substring(0, 1).ToUpper() + tmp.Substring(1);
						return tmp;
					}
					if (tram != 0 & chuc == 0)
					{
						if (dv != 0)
						{
							tmp = chuso[tram] + " trăm lẻ " + chuso[dv] + " " + DVT;
						}
						else
						{
							tmp = chuso[tram] + " trăm " + DVT;
						}
						//tmp = Microsoft.VisualBasic.Left(tmp, 1).ToUpper + tmp.Substring(1);
						tmp = tmp.Substring(0, 1).ToUpper() + tmp.Substring(1);
						return tmp;
					}
					if (chuc == 1)
					{
						if (dv != 0)
						{
							if (dv == 5)
							{
								tmp = "mười lăm " + DVT;
							}
							else
							{
								tmp = "mười " + chuso[dv] + " " + DVT;
							}
						}
						else
						{
							tmp = "mười " + DVT;
						}
					}
					else
					{
						if (dv != 0)
						{
							if (dv == 5)
							{
								tmp = chuso[chuc] + " mươi lăm " + DVT;
							}
							else if (dv == 1)
							{
								tmp = chuso[chuc] + " mươi mốt " + DVT;
							}
							else
							{
								tmp = chuso[chuc] + " mươi " + chuso[dv] + " " + DVT;
							}
						}
						else
						{
							tmp = chuso[chuc] + " mươi " + DVT;
						}
					}
					if (tram != 0)
					{
						tmp = chuso[tram] + " trăm " + tmp;
						//tmp = Microsoft.VisualBasic.Left(tmp, 1).ToUpper + tmp.Substring(1);
						tmp = tmp.Substring(0, 1).ToUpper() + tmp.Substring(1);
						return tmp;
					}
					else
					{
						//tmp = Microsoft.VisualBasic.Left(tmp, 1).ToUpper + tmp.Substring(1);
						tmp = tmp.Substring(0, 1).ToUpper() + tmp.Substring(1);
						return tmp;
					}
				}
			}
		}
		#endregion

		/// <summary>
		/// Extract a substring.
		/// Ex: 
		///		Extract("00|33;aaa|bbb;ccc", "|", ";", 0, int.MaxValue) will return "33".
		///		Extract("00|33;aaa|bbb;ccc", "|", ";", 5, int.MaxValue) will return "bbb".
		/// </summary>
		/// <param name="strSource"></param>
		/// <param name="strSeparatorBegin"></param>
		/// <param name="strSeparatorEnd"></param>
		/// <param name="nStart"></param>
		/// <param name="nCount"></param>
		/// <returns></returns>
		public static string Extract(string strSource, string strSeparatorBegin, string strSeparatorEnd, int nStart, int nCount)
		{
			if (strSource == null) return null;
			if (nCount > strSource.Length - nStart)
				nCount = strSource.Length - nStart;
			int nPos = strSource.IndexOf(strSeparatorBegin, nStart, nCount);
			if (nPos < 0) return null;
			int nPosBegin = nPos + strSeparatorBegin.Length;
			int nPosEnd = strSource.IndexOf(strSeparatorEnd, nPosBegin);
			if (nPosEnd < 0) return null;
			return strSource.Substring(nPosBegin, nPosEnd - nPosBegin - 1);
		}
		/// <summary>
		/// Extract a substring.
		/// Ex: 
		///		Extract("00|33;aaa|bbb;ccc", "|", ";", 0, int.MaxValue) will return "33".
		///		Extract("00|33;aaa|bbb;ccc", "|", ";", 5, int.MaxValue) will return "bbb".
		/// </summary>
		/// <param name="strSource"></param>
		/// <param name="strSeparatorBegin"></param>
		/// <param name="strSeparatorEnd"></param>
		/// <param name="nStart"></param>
		/// <param name="nCount"></param>
		/// <returns></returns>
		public static string Extract(string strSource, string strSeparatorBegin, string strSeparatorEnd, int nStart)
		{
			return Extract(strSource, strSeparatorBegin, strSeparatorEnd, nStart, int.MaxValue);
		}
		/// <summary>
		/// Extract a substring.
		/// Ex: 
		///		Extract("00|33;aaa|bbb;ccc", "|", ";", 0, int.MaxValue) will return "33".
		///		Extract("00|33;aaa|bbb;ccc", "|", ";", 5, int.MaxValue) will return "bbb".
		/// </summary>
		/// <param name="strSource"></param>
		/// <param name="strSeparatorBegin"></param>
		/// <param name="strSeparatorEnd"></param>
		/// <param name="nStart"></param>
		/// <param name="nCount"></param>
		/// <returns></returns>
		public static string Extract(string strSource, string strSeparatorBegin, string strSeparatorEnd)
		{
			return Extract(strSource, strSeparatorBegin, strSeparatorEnd, 0, int.MaxValue);
		}

		/// <summary>
		/// Split a string to some substrings.
		/// Ex: 
		///		Split("|aaa;|bbb;|ccc;", "|", ";") will return {"aaa", "bbb", "ccc"}.
		///		Split("aaa;|bbb;|ccc", "|", ";") will return {"aaa", "bbb", "ccc"}.
		/// </summary>
		/// <param name="strSource"></param>
		/// <param name="strSeparatorBegin"></param>
		/// <param name="strSeparatorEnd"></param>
		/// <returns></returns>
		public static string[] Split(string strSource, string strSeparatorBegin, string strSeparatorEnd)
		{
			// Temp:
			string[] arrstrResult = null;

			// Process:
			arrstrResult = strSource.Split(new string[] { strSeparatorEnd + strSeparatorEnd }, int.MaxValue, StringSplitOptions.None);
			if (arrstrResult != null)
			{
				int nPos = 0;
				nPos = arrstrResult[0].IndexOf(strSeparatorBegin);
				if (nPos >= 0)
				{
					arrstrResult[0] = arrstrResult[0].Substring(nPos + strSeparatorBegin.Length);
				}
				nPos = arrstrResult[arrstrResult.Length - 1].IndexOf(strSeparatorEnd);
				if (nPos >= 0)
				{
					arrstrResult[arrstrResult.Length - 1] = arrstrResult[arrstrResult.Length - 1].Substring(0, nPos);
				}
			}

			// Return Good:
			return arrstrResult;
		}

		/// <summary>
		/// Build a string contains list of items.
		/// Ex: 
		///		BuildList({"aaa", "bbb", "ccc"}, "|", "|", ";") will return "|aaa|;|bbb|;|ccc|".
		/// </summary>
		/// <param name="alItemList">List of items.</param>
		/// <param name="strBeginBound">Begin bound of an item.</param>
		/// <param name="strEndBound">End bound of an item.</param>
		/// <param name="strSeparator">Separator between 2 items.</param>
		/// <returns>String contains list of items.</returns>
		public static string BuildList(ArrayList alItemList, string strBeginBound, string strEndBound, string strSeparator)
		{
			// Temp:
			if (alItemList == null || alItemList.Count == 0) return null;

			// Process:
			StringBuilder strbdItemList = new StringBuilder(5000);
			for (int i = 0; i < alItemList.Count; i++)
			{
				strbdItemList.AppendFormat("{0}{1}{2}{3}", strBeginBound, alItemList[i], strEndBound, strSeparator);
			}
			string strItemList = strbdItemList.ToString(0, strbdItemList.Length - strSeparator.Length);

			// Return Good:
			return strItemList;
		}
		/// <summary>
		/// Find and Replace contents of a string.
		/// Ex: 
		///		Replace("aaabbbccc", {"aaa", "111", "bbb", "222"}) will return "111222ccc".
		/// </summary>
		/// <param name="strSource"></param>
		/// <param name="arrobjCouple"></param>
		/// <returns></returns>
		public static string Replace(string strSource, params object[] arrobjCouple)
		{
			if (strSource == null || string.Equals(strSource, "")) return "";
			if (arrobjCouple == null || arrobjCouple.Length < 1) return strSource;
			StringBuilder strbd = new StringBuilder(strSource);
			for (int i = 0; i < arrobjCouple.Length; i += 2)
			{
				strbd.Replace(Convert.ToString(arrobjCouple[i]), Convert.ToString(arrobjCouple[i + 1]));
			}
			return strbd.ToString();
		}

		public static bool StringEqual(object obj1, object obj2)
		{
			return (string.Equals(Convert.ToString(obj1), Convert.ToString(obj2)));
		}
		public static bool StringEqual(object obj1, object obj2, bool bIgnoreCase)
		{
			return (string.Compare(Convert.ToString(obj1), Convert.ToString(obj2), bIgnoreCase) == 0);
		}
		public static bool StringEqualIgnoreCase(object obj1, object obj2)
		{
			return (string.Compare(Convert.ToString(obj1), Convert.ToString(obj2), true) == 0);
		}
		public static int StringCompare(object obj1, object obj2)
		{
			return (string.Compare(Convert.ToString(obj1), Convert.ToString(obj2)));
		}
		public static int StringCompare(object obj1, object obj2, bool bIgnoreCase)
		{
			return (string.Compare(Convert.ToString(obj1), Convert.ToString(obj2), bIgnoreCase));
		}
		public static int StringCompareIgnoreCase(object obj1, object obj2)
		{
			return (string.Compare(Convert.ToString(obj1), Convert.ToString(obj2), true));
		}

		public static string GetParentDir(object objPath)
		{ 
			// Init:
			string strResult = "";

			// Check:
			if (objPath == null) return strResult;
			string strPath = Convert.ToString(objPath).Trim(' ', '\\');
			int nPos = strPath.LastIndexOf('\\');
			if (nPos <= 0) return strResult;

			// Assign:
			strResult = strPath.Substring(0, nPos);

			// Return Good:
			return strResult;
		}
		public static void SplitByDelimiterFromLast(object objSource, string strDelimiter, out string strPrefix, out string strPostfix)
		{
			strPrefix = "";
			strPostfix = "";
			string strSource = string.Format("{0}", objSource);
			int nPos = strSource.LastIndexOf(strDelimiter);
			if (nPos >= 0)
			{
				strPrefix = strSource.Substring(0, nPos);
				if (nPos < strSource.Length - strDelimiter.Length) strPostfix = strSource.Substring(nPos + strDelimiter.Length);
			}
			else
			{
				strPrefix = strSource;
			}
		}

		public static bool IsEmpty(string str)
		{
			return (str == null || str.Trim().Length < 1);
		}

		public static byte[] String2ArrayBytes(Encoding e, string strSource)
		{
			return e.GetBytes(strSource);
		}
		public static byte[] String2ArrayBytes(Encoding e, string strSource, int nIdx)
		{
			return e.GetBytes(strSource.Substring(nIdx));
		}
		public static byte[] String2ArrayBytes(Encoding e, string strSource, int nIdx, int nCount)
		{
			return e.GetBytes(strSource.Substring(nIdx, nCount));
		}
		public static string ArrayBytes2String(Encoding e, byte[] arrbyteSource)
		{
			return e.GetString(arrbyteSource, 0, arrbyteSource.Length);
		}
		public static string ArrayBytes2String(Encoding e, byte[] arrbyteSource, int nIdx)
		{
			return e.GetString(arrbyteSource, nIdx, arrbyteSource.Length - nIdx);
		}
		public static string ArrayBytes2String(Encoding e, byte[] arrbyteSource, int nIdx, int nCount)
		{
			return e.GetString(arrbyteSource, nIdx, nCount);
		}
		public static string String2Base64(Encoding e, string strSource)
		{
			byte[] arrbyteSource = String2ArrayBytes(e, strSource);
			return Convert.ToBase64String(arrbyteSource);
		}
		public static string String2Base64(Encoding e, string strSource, int nIdx)
		{
			byte[] arrbyteSource = String2ArrayBytes(e, strSource, nIdx);
			return Convert.ToBase64String(arrbyteSource);
		}
		public static string String2Base64(Encoding e, string strSource, int nIdx, int nCount)
		{
			byte[] arrbyteSource = String2ArrayBytes(e, strSource, nIdx, nCount);
			return Convert.ToBase64String(arrbyteSource);
		}
		public static string Base64ToString(Encoding e, string strSource)
		{
			byte[] arrbyteSource = Convert.FromBase64String(strSource);
			return e.GetString(arrbyteSource);
		}
		public static string Base64ToString(Encoding e, string strSource, int nIdx)
		{
			byte[] arrbyteSource = Convert.FromBase64String(strSource.Substring(nIdx));
			return e.GetString(arrbyteSource);
		}
		public static string Base64ToString(Encoding e, string strSource, int nIdx, int nCount)
		{
			byte[] arrbyteSource = Convert.FromBase64String(strSource.Substring(nIdx, nCount));
			return e.GetString(arrbyteSource);
		}
	}

	public class DateTimeUtils
	{
		/// <summary>
		/// Return the the first Date of Next n month.
		/// Ex: 
		///		AddMonths({2000-05-16}, 10) will return {2001-03-01}.
		/// </summary>
		/// <param name="dtime"></param>
		/// <param name="nMonth"></param>
		/// <returns></returns>
		public static DateTime AddMonths(DateTime dtime, int nMonth)
		{
			int nSum = dtime.Year * 12 + dtime.Month - 1 + nMonth;
			DateTime dtimeNew = new DateTime(nSum / 12, nSum % 12 + 1, 1);
			return dtimeNew;
		}
		/// <summary>
		/// Convert a String to DateTime.
		/// The StandardFormat: "yyyy-MM-dd HH:mm:ss.fff"
		/// Ex: 
		///		String2DateTime("2000-05-16 151617 123", "yyyy-MM-dd HHmmss fff") will return {2000-05-16 15:16:17.123}.
		///		String2DateTime("2000-05-16 1516", "yyyy-MM-dd HHmm") will return {2000-05-16 15:16:00.000}.
		/// </summary>
		/// <param name="strValue"></param>
		/// <param name="strFormat"></param>
		/// <returns></returns>
		public static DateTime String2DateTime(string strValue, string strFormat)
		{
			//System.Globalization.DateTimeFormatInfo dtfi = new System.Globalization.DateTimeFormatInfo();
			//dtfi.ShortDatePattern = strFormat;
			//return DateTime.Parse(strValue, dtfi);

			// Temp: The standard format template: "yyyy-MM-dd HH:mm:ss.fff"
			strFormat = strFormat.Replace("MM", "x1").Replace("HH", "x2").ToLower().Replace("x1", "MM").Replace("x2", "HH");
			int nPos = 0;

			// Process:
			nPos = strFormat.IndexOf("yyyy"); int nYear = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 4));
			nPos = strFormat.IndexOf("MM"); int nMonth = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 2));
			nPos = strFormat.IndexOf("dd"); int nDay = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 2));
			nPos = strFormat.IndexOf("hh"); int nHour = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 2));
			nPos = strFormat.IndexOf("mm"); int nMinute = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 2));
			nPos = strFormat.IndexOf("ss"); int nSecond = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 2));
			nPos = strFormat.IndexOf("fff"); int nMillisecond = Convert.ToInt32(nPos < 0 ? "0" : strValue.Substring(nPos, 3));

			// Return Good:
			return new DateTime(nYear, nMonth, nDay, nHour, nMinute, nSecond, nMillisecond);
		}

		public static TimeSpan Minus(object objDateTime1, object objDateTime2)
		{ 
			return (Convert.ToDateTime(objDateTime1) - Convert.ToDateTime(objDateTime2));
		}
	}

	public class Registry
	{
		public const string c_strHKEY_CLASSES_ROOT = "HKEY_CLASSES_ROOT";
		public const string c_strHKEY_CURRENT_USER = "HKEY_CURRENT_USER";
		public const string c_strHKEY_LOCAL_MACHINE = "HKEY_LOCAL_MACHINE";
		public const string c_strHKEY_USERS = "HKEY_USERS";
		public const string c_strHKEY_CURRENT_CONFIG = "HKEY_CURRENT_CONFIG";

		public static void SetKey(string strKeyFullPath, string strKeyItemName, object objKeyItemValue)
		{
			Microsoft.Win32.Registry.SetValue(strKeyFullPath, strKeyItemName, objKeyItemValue);
		}
		public static void SetKey(string strKeyFullPath, string strKeyItemName, object objKeyItemValue, Microsoft.Win32.RegistryValueKind rvkItemType)
		{
			Microsoft.Win32.Registry.SetValue(strKeyFullPath, strKeyItemName, objKeyItemValue, rvkItemType);
		}

		public static object GetKey(string strKeyFullPath, string strKeyItemName, object objDefaultIfNotFound)
		{
			return Microsoft.Win32.Registry.GetValue(strKeyFullPath, strKeyItemName, objDefaultIfNotFound);
		}
	}

	public class OperatorUtils
	{
		public static double ConvertToDouble(object v, int nPrecision)
		{
			return Math.Round(Convert.ToDouble(v), nPrecision);
		}
		public static double ConvertToDouble(double v)
		{
			return Math.Round(v, 9);
		}
		public static double ConvertToDouble(object v)
		{
			return Math.Round(Convert.ToDouble(v), 9);
		}
		new public static bool Equals(object dblV1, object dblV2)
		{
			return (ConvertToDouble(dblV1) - ConvertToDouble(dblV2) == 0.0);
		}

		public static double Plus(object a, object b)
		{
			if (a == null || a == DBNull.Value) a = 0;
			if (b == null || b == DBNull.Value) b = 0;
			return ConvertToDouble(Convert.ToDouble(a) + Convert.ToDouble(b));
		}
		public static double Minus(object a, object b)
		{
			if (a == null || a == DBNull.Value) a = 0;
			if (b == null || b == DBNull.Value) b = 0;
			return ConvertToDouble(Convert.ToDouble(a) - Convert.ToDouble(b));
		}
		public static double Multi(object a, object b)
		{
			if (a == null || a == DBNull.Value) a = 0;
			if (b == null || b == DBNull.Value) b = 0;
			return ConvertToDouble(Convert.ToDouble(a) * Convert.ToDouble(b));
		}
		public static double Divide(object a, object b)
		{
			if (a == null || a == DBNull.Value) a = 0;
			if (b == null || b == DBNull.Value) b = 0;
			if (Convert.ToDouble(a) == 0 && Convert.ToDouble(b) == 0) return 1;
			return ConvertToDouble(Convert.ToDouble(a) / Convert.ToDouble(b));
		}

		public static double CalcStairInterest(double dblValue, double dblLastInterest, params double[] arrdblCoupleParams)
		{ 
			// Temp:
			double dblResult = 0.0;
			if (arrdblCoupleParams == null || arrdblCoupleParams.Length == 0) return ConvertToDouble(dblValue * dblLastInterest);

			// Scan interest list until matched:
			double dblMark = 0.0;
			int i = 0;
			for (i = 0; (i < arrdblCoupleParams.Length) && (dblValue > arrdblCoupleParams[i]); i += 2)
			{
				dblResult += (arrdblCoupleParams[i] - dblMark) * arrdblCoupleParams[i + 1];
				dblMark = arrdblCoupleParams[i];
			}
			dblResult += (i < arrdblCoupleParams.Length ? arrdblCoupleParams[i + 1]: dblLastInterest) * (dblValue - dblMark);

			// Return Good:
			return ConvertToDouble(dblResult);
		}
	}

	public class XmlUtils
	{
		public static XmlDocument String2XMLDocument(string strXml)
		{
			XmlDocument xd = new XmlDocument();
			xd.LoadXml(strXml);
			return xd;
		}
		public static string GetFirstNodeContent(XmlDocument xd, string strTagNodeName)
		{
			XmlNodeList xnl = xd.GetElementsByTagName(strTagNodeName);
			return xnl[0].InnerText;
		}
		public static string GetFirstNodeContent(string strXml, string strTagNodeName)
		{
			XmlDocument xd = new XmlDocument();
			xd.LoadXml(strXml);
			XmlNodeList xnl = xd.GetElementsByTagName(strTagNodeName);
			return xnl[0].InnerText;
		}
		public static XmlNodeList GetNodes(XmlDocument xd, string strTagNodeName)
		{
			return xd.GetElementsByTagName(strTagNodeName);
		}
		public static string[] GetNodesContents(XmlDocument xd, string strTagNodeName)
		{
			XmlNodeList xnl = xd.GetElementsByTagName(strTagNodeName);
			if (xnl == null) return null;
			string[] arrstr = new string[xnl.Count];
			for (int i = 0; i < xnl.Count; i++)
			{
				arrstr[i] = xnl[i].InnerText;
			}
			return arrstr;
		}
		public static string[] GetNodesContents(string strXml, string strTagNodeName)
		{
			XmlDocument xd = new XmlDocument();
			xd.LoadXml(strXml);
			XmlNodeList xnl = xd.GetElementsByTagName(strTagNodeName);
			if (xnl == null) return null;
			string[] arrstr = new string[xnl.Count];
			for (int i = 0; i < xnl.Count; i++)
			{
				arrstr[i] = xnl[i].InnerText;
			}
			return arrstr;
		}

		public static string DataSet2Xml(DataSet ds)
		{
			if (ds == null) return "";
			using (System.IO.StringWriter sw = new System.IO.StringWriter())
			{
				ds.WriteXml(sw, XmlWriteMode.WriteSchema);
				return sw.ToString();
			}
		}
		public static string DataSet2Xml(DataSet ds, XmlWriteMode xwm)
		{
			if (ds == null) return "";
			using (System.IO.StringWriter sw = new System.IO.StringWriter())
			{
				ds.WriteXml(sw, xwm);
				return sw.ToString();
			}
		}
		public static string DataSet2XmlSimple(DataSet ds)
		{
			// Check:
			if (ds == null) return "";

			// Init:
			StringBuilder strbdBody = new StringBuilder();
			string strTagTemplate = "<{0}>{1}</{0}>";

			// Build the DataSetBody:
			for (int k = 0; k < ds.Tables.Count; k++)
			{
				DataTable dt = ds.Tables[k];
				for (int i = 0; i < dt.Rows.Count; i++)
				{
					string strRow = "";
					for (int j = 0; j < dt.Columns.Count; j++)
					{
						object objCellValue = dt.Rows[i][j];
						if (dt.Columns[j].DataType == typeof(DateTime))
						{
							try
							{
								objCellValue = Convert.ToDateTime(dt.Rows[i][j]).ToString("yyyy-MM-dd HH:mm:ss");
							}
							catch
							{
								objCellValue = DBNull.Value;
							}
						}
						if (dt.Columns[j].DataType == typeof(byte[]))
						{
							try
							{
								objCellValue = Convert.ToBase64String(Encoding.Unicode.GetBytes(Convert.ToString(objCellValue)));
							}
							catch
							{
								objCellValue = DBNull.Value;
							}
						}
						strRow += string.Format(strTagTemplate, dt.Columns[j].ColumnName, objCellValue);
					}
					strbdBody.AppendFormat(strTagTemplate, dt.TableName, strRow);
				}
			}
			string strResult = string.Format(strTagTemplate, ds.DataSetName, strbdBody);

			// Return Good:
			return strResult;
		}
		public static DataSet Xml2DataSet(string strXml)
		{
			try
			{
				using (System.IO.StringReader sr = new System.IO.StringReader(strXml))
				{
					DataSet ds = new DataSet();
					ds.ReadXml(sr, XmlReadMode.Auto);
					return ds;
				}
			}
			catch
			{
				return null;
			}
		}
		public static DataSet Xml2DataSet(object strXml)
		{
			try
			{
				using (System.IO.StringReader sr = new System.IO.StringReader(Convert.ToString(strXml)))
				{
					DataSet ds = new DataSet();
					ds.ReadXml(sr, XmlReadMode.Auto);
					return ds;
				}
			}
			catch
			{
				return null;
			}
		}
	}

	public class CollectionUtils
	{
		public static Hashtable ParamsCouple2Hashtable(bool bUpperCase, params object[] arrobjParamsCouple)
		{
			// Temp:
			Hashtable htParams = new Hashtable();
			if (arrobjParamsCouple == null || arrobjParamsCouple.Length <= 0) return htParams;
			if (bUpperCase)
			{
				for (int i = 0; i < arrobjParamsCouple.Length; i += 2)
				{
					htParams.Add(Convert.ToString(arrobjParamsCouple[i]).ToUpper(), arrobjParamsCouple[i + 1]);
				}
			}
			else
			{
				for (int i = 0; i < arrobjParamsCouple.Length; i += 2)
				{
					htParams.Add(arrobjParamsCouple[i], arrobjParamsCouple[i + 1]);
				}
			}

			// Return Good:
			return htParams;
		}
	}

	public class MailUtils
	{
		public void SendMail(string strMailServer, string strFrom, string strTo, string strSubject, string strContents, bool bIgnoreError)
		{
			try
			{
				System.Net.Mail.MailMessage mm = new System.Net.Mail.MailMessage(strFrom, strTo, strSubject, strContents);
				System.Net.Mail.SmtpClient c = new System.Net.Mail.SmtpClient(strMailServer);
				c.Send(mm);
			}
			catch
			{
				if (!bIgnoreError) throw;
			}
		}
	}

	public class ValidateUtils
	{
		/// <summary>
		/// Check validate the Params.
		/// Ex: 
		///	arrobjTripleCheckParams = 
		///	{
		///		"a", true, {"a", "b"} ("a" must be in {"a", "b"} => Ok)
		///		, "c", false, {"a", "b"} ("c" must be not in {"a", "b"} => Ok)
		///		, "x", true, {"a", "b"} ("x" must be in {"a", "b"} => Fail)
		///	}
		///	ValidateParams will return 2 (Position of the FirstTripleParam Fail).
		///	Case done for all then return -1.
		/// </summary>
		/// <param name="arrobjTripleCheckParams"></param>
		/// <returns></returns>
		public static int ValidateParams(params object[] arrobjTripleCheckParams)
		{
			// Process:
			for (int i = 0; i < arrobjTripleCheckParams.Length / 3; i++)
			{
				object objCheck = arrobjTripleCheckParams[i * 3];
				bool bCheckInList = Convert.ToBoolean(arrobjTripleCheckParams[i * 3 + 1]);
				ArrayList alCheck = new ArrayList((ICollection)arrobjTripleCheckParams[i * 3 + 2]);
				if (bCheckInList && !alCheck.Contains(objCheck)
					|| !bCheckInList && alCheck.Contains(objCheck)
					)
					return i;
			}

			// Return Good:
			return -1;
		}
	}

	public class ThreadUtils
	{
		private static Hashtable s_htResource = new Hashtable();
		private static Hashtable s_htThreadQueueList = new Hashtable();
		/// <summary>
		/// The algorithm for manager n thread sharing the critical resource.
		/// Only thread take the resource can run the work.
		/// The resource only free when the work done.
		/// Notes:
		///		This algorithm solve the problem: a thread waiting infinitive.
		///		If the ResourceId not exist then create new.
		/// </summary>
		/// <param name="strResourceId"></param>
		/// <param name="strThreadId"></param>
		/// <param name="bCancelWaiting"></param>
		/// <param name="func"></param>
		/// <param name="objParam"></param>
		public static bool LockResourceAndRun(
			string strResourceId
			, string strThreadId
			, ref bool bCancelWaiting
			, ParameterizedThreadStart func
			, ref object objParam
			)
		{ 
			// Create new Resource if not exist:
			if (bCancelWaiting) return false;
			strResourceId = strResourceId.ToUpper();
			strThreadId = strThreadId.ToUpper();
			if (!s_htResource.ContainsKey(strResourceId))
			{
				lock (s_htResource)
				{
					// Recheck:
					if (!s_htResource.ContainsKey(strResourceId))
					{
						s_htResource.Add(strResourceId, new object());
						s_htThreadQueueList.Add(strResourceId, new ArrayList());
					}
				}
			}

			// Register Thread to Queue:
			if (bCancelWaiting) return false;
			ArrayList alThreadQueue = (ArrayList)s_htThreadQueueList[strResourceId];
			lock (alThreadQueue)
			{
				alThreadQueue.Add(strThreadId);
			}

			#region // Try to Lock resource and Run:
			// Check:
			int nPos = alThreadQueue.IndexOf(strThreadId);
			while (!bCancelWaiting && nPos > 0)
			{
				Thread.Sleep(1); // milliseconds.
				//Thread.Sleep(nPos); // milliseconds.
				//Thread.Sleep(new TimeSpan(nPos)); // ticks (100_nanoseconds = 100 * 10^-9 seconds).
				nPos = alThreadQueue.IndexOf(strThreadId);
			}
			if (bCancelWaiting)
			{
				lock (alThreadQueue)
				{
					// Remove the registration:
					alThreadQueue.Remove(strThreadId);
					return false;
				}
			}
			if (nPos < 0) return false;

			// Do the work:
			try
			{
				func(objParam);
			}
			finally
			{
				// Remove the registration:
				lock (alThreadQueue)
				{
					alThreadQueue.Remove(strThreadId);
				}
			}
			#endregion

			// Return Good:
			return true;
		}

		public static void CancelWaiting(
			string strResourceId
			, string strThreadId
			)
		{
			// Check:
			strResourceId = strResourceId.ToUpper();
			strThreadId = strThreadId.ToUpper();
			if (!s_htResource.ContainsKey(strResourceId)) return;
			ArrayList alThreadQueue = (ArrayList)s_htThreadQueueList[strResourceId];
			if (alThreadQueue.Contains(strThreadId))
			{
				// Remove the registration:
				lock (alThreadQueue)
				{
					alThreadQueue.Remove(strThreadId);
				}
			}
		}
	}

	public class ProcessUtils
	{
		/// <summary>
		/// Start a Process and Wait to End within MaxTime.
		/// </summary>
		/// <param name="strFileName">
		/// ExeFile or SupportedFile.
		///		Ex: a.Exe, b.Txt, c.Doc, d.Xls, e.Pdf, ...
		/// </param>
		/// <param name="strArgumentList">
		/// ArgumentList
		/// </param>
		/// <param name="nMaxWaitMilliseconds">
		/// MaxTime to Wait.
		///		Ex: 0 => StartProcess with NoWait and continue my work.
		///			-1 => StartProcess and Wait until ProcessFinished.
		/// </param>
		/// <returns>
		/// Return null when StartInit error.
		/// Case StartInit successful, return the process.
		/// </returns>
		public static Process StartProcessAndWait(
			string strFileName
			, string strArgumentList
			//, bool bUseOSShellExecute
			, int nMaxWaitMilliseconds
			)
		{
			// Init:
			ProcessStartInfo psi = new ProcessStartInfo();
			psi.FileName = strFileName;
			psi.Arguments = strArgumentList;
			//psi.UseShellExecute = bUseOSShellExecute;

			// Run and Wait:
			Process p = Process.Start(psi);
			if (p == null) return null;
			//p.WaitForInputIdle(); // Wait for finish loading.
			p.WaitForExit(nMaxWaitMilliseconds); // Wait for Exit with MaxTime.

			// Return ExistingProcess:
			return p;
		}
	}

	public class FileUtils
	{
		public static string ReadAllText(string strFilePath)
		{
			// Init:
			string strResult = "";
			//strResult = File.ReadAllText(strFilePath); // This function sometimes has error when case multi access.
			using (FileStream fs = File.Open(strFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
			{
				using (StreamReader sr = new StreamReader(fs))
				{
					strResult = sr.ReadToEnd();
					sr.Close();
				}
				fs.Close();
			}

			// Return Good:
			return strResult;
		}
		public static void AppendAllText(string strFilePath, string strContents, Encoding e)
		{
			// Init:
			//File.AppendAllText(strFilePath, strContents, e); // This function sometimes has error when case multi access.
			using (FileStream fs = File.Open(strFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
			{
				fs.Seek(fs.Length, SeekOrigin.Begin);
				using (StreamWriter sw = new StreamWriter(fs, e))
				{
					sw.Write(strContents);
					sw.Close();
				}
				fs.Close();
			}
		}
	}
} // namespace CommonUtils
